// // Copyright 2014 The Flutter Authors. All rights reserved.
// // Use of this source code is governed by a BSD-style license that can be
// // found in the LICENSE file.
//
// import 'dart:math' as math;
//
// import 'package:flutter/foundation.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter/rendering.dart';
// import 'package:flutter/services.dart';
// import 'package:flutter/widgets.dart';
//
// const Duration _kDropdownMenuDuration = Duration(milliseconds: 300);
// const double _kMenuItemHeight = kMinInteractiveDimension;
// const double _kDenseButtonHeight = 24.0;
// const EdgeInsets _kMenuItemPadding = EdgeInsets.symmetric(horizontal: 16.0);
// const EdgeInsetsGeometry _kAlignedButtonPadding = EdgeInsetsDirectional.only(start: 16.0, end: 4.0);
// const EdgeInsets _kUnalignedButtonPadding = EdgeInsets.zero;
// const EdgeInsets _kAlignedMenuMargin = EdgeInsets.zero;
// const EdgeInsetsGeometry _kUnalignedMenuMargin = EdgeInsetsDirectional.only(start: 16.0, end: 24.0);
//
// /// A builder to customize dropdown buttons.
// ///
// /// Used by [DropdownButton.selectedItemBuilder].
// typedef DropdownButtonBuilder = List<Widget> Function(BuildContext context);
//
// class _DropdownMenuPainter extends CustomPainter {
//   _DropdownMenuPainter({
//     this.color,
//     this.elevation,
//     this.selectedIndex,
//     this.borderRadius,
//     required this.resize,
//     required this.getSelectedItemOffset,
//   }) : _painter = BoxDecoration(
//          // If you add an image here, you must provide a real
//          // configuration in the paint() function and you must provide some sort
//          // of onChanged callback here.
//          color: color,
//          borderRadius: borderRadius ?? const BorderRadius.all(Radius.circular(2.0)),
//          boxShadow: kElevationToShadow[elevation],
//        ).createBoxPainter(),
//        super(repaint: resize);
//
//   final Color? color;
//   final int? elevation;
//   final int? selectedIndex;
//   final BorderRadius? borderRadius;
//   final Animation<double> resize;
//   final ValueGetter<double> getSelectedItemOffset;
//   final BoxPainter _painter;
//
//   @override
//   void paint(Canvas canvas, Size size) {
//     final double selectedItemOffset = getSelectedItemOffset();
//     final Tween<double> top = Tween<double>(
//       begin: clampDouble(selectedItemOffset, 0.0, math.max(size.height - _kMenuItemHeight, 0.0)),
//       end: 0.0,
//     );
//
//     final Tween<double> bottom = Tween<double>(
//       begin: clampDouble(top.begin! + _kMenuItemHeight, math.min(_kMenuItemHeight, size.height), size.height),
//       end: size.height,
//     );
//
//     final Rect rect = Rect.fromLTRB(0.0, top.evaluate(resize), size.width, bottom.evaluate(resize));
//
//     _painter.paint(canvas, rect.topLeft, ImageConfiguration(size: rect.size));
//   }
//
//   @override
//   bool shouldRepaint(_DropdownMenuPainter oldPainter) {
//     return oldPainter.color != color
//         || oldPainter.elevation != elevation
//         || oldPainter.selectedIndex != selectedIndex
//         || oldPainter.borderRadius != borderRadius
//         || oldPainter.resize != resize;
//   }
// }
//
// // The widget that is the button wrapping the menu items.
// class _DropdownMenuItemButton<T> extends StatefulWidget {
//   const _DropdownMenuItemButton({
//     super.key,
//     this.padding,
//     required this.route,
//     required this.buttonRect,
//     required this.constraints,
//     required this.itemIndex,
//     required this.enableFeedback,
//   });
//
//   final _DropdownRoute<T> route;
//   final EdgeInsets? padding;
//   final Rect buttonRect;
//   final BoxConstraints constraints;
//   final int itemIndex;
//   final bool enableFeedback;
//
//   @override
//   _DropdownMenuItemButtonState<T> createState() => _DropdownMenuItemButtonState<T>();
// }
//
// class _DropdownMenuItemButtonState<T> extends State<_DropdownMenuItemButton<T>> {
//   void _handleFocusChange(bool focused) {
//     final bool inTraditionalMode;
//     switch (FocusManager.instance.highlightMode) {
//       case FocusHighlightMode.touch:
//         inTraditionalMode = false;
//         break;
//       case FocusHighlightModeaditional:
//         inTraditionalMode = true;
//         break;
//     }
//
//     if (focused && inTraditionalMode) {
//       final _MenuLimits menuLimits = widget.route.getMenuLimits(
//         widget.buttonRect,
//         widget.constraints.maxHeight,
//         widget.itemIndex,
//       );
//       widget.route.scrollController!.animateTo(
//         menuLimits.scrollOffset,
//         curve: Curves.easeInOut,
//         duration: const Duration(milliseconds: 100),
//       );
//     }
//   }
//
//   void _handleOnTap() {
//     final DropdownMenuItem<T> dropdownMenuItem = widget.route.items[widget.itemIndex].item!;
//
//     dropdownMenuItem.onTap?.call();
//
//     Navigator.pop(
//       context,
//       _DropdownRouteResult<T>(dropdownMenuItem.value),
//     );
//   }
//
//   static const Map<ShortcutActivator, Intent> _webShortcuts = <ShortcutActivator, Intent>{
//     // On the web, up/down don't change focus, *except* in a <select>
//     // element, which is what a dropdown emulates.
//     SingleActivator(LogicalKeyboardKey.arrowDown): DirectionalFocusIntent(TraversalDirection.down),
//     SingleActivator(LogicalKeyboardKey.arrowUp): DirectionalFocusIntent(TraversalDirection.up),
//   };
//
//   @override
//   Widget build(BuildContext context) {
//     final DropdownMenuItem<T> dropdownMenuItem = widget.route.items[widget.itemIndex].item!;
//     final CurvedAnimation opacity;
//     final double unit = 0.5 / (widget.route.items.length + 1.5);
//     if (widget.itemIndex == widget.route.selectedIndex) {
//       opacity = CurvedAnimation(parent: widget.route.animation!, curve: const Threshold(0.0));
//     } else {
//       final double start = clampDouble(0.5 + (widget.itemIndex + 1) * unit, 0.0, 1.0);
//       final double end = clampDouble(start + 1.5 * unit, 0.0, 1.0);
//       opacity = CurvedAnimation(parent: widget.route.animation!, curve: Interval(start, end));
//     }
//     Widget child = Container(
//       padding: widget.padding,
//       height: widget.route.itemHeight,
//       child: widget.route.items[widget.itemIndex],
//     );
//     // An [InkWell] is added to the item only if it is enabled
//     if (dropdownMenuItem.enabled) {
//       child = InkWell(
//         autofocus: widget.itemIndex == widget.route.selectedIndex,
//         enableFeedback: widget.enableFeedback,
//         onTap: _handleOnTap,
//         onFocusChange: _handleFocusChange,
//         child: child,
//       );
//     }
//     child = FadeTransition(opacity: opacity, child: child);
//     if (kIsWeb && dropdownMenuItem.enabled) {
//       child = Shortcuts(
//         shortcuts: _webShortcuts,
//         child: child,
//       );
//     }
//     return child;
//   }
// }
//
// class _DropdownMenu<T> extends StatefulWidget {
//   const _DropdownMenu({
//     super.key,
//     this.padding,
//     required this.route,
//     required this.buttonRect,
//     required this.constraints,
//     this.dropdownColor,
//     required this.enableFeedback,
//     this.borderRadius,
//   });
//
//   final _DropdownRoute<T> route;
//   final EdgeInsets? padding;
//   final Rect buttonRect;
//   final BoxConstraints constraints;
//   final Color? dropdownColor;
//   final bool enableFeedback;
//   final BorderRadius? borderRadius;
//
//   @override
//   _DropdownMenuState<T> createState() => _DropdownMenuState<T>();
// }
//
// class _DropdownMenuState<T> extends State<_DropdownMenu<T>> {
//   late CurvedAnimation _fadeOpacity;
//   late CurvedAnimation _resize;
//
//   @override
//   void initState() {
//     super.initState();
//     // We need to hold these animations as state because of their curve
//     // direction. When the route's animation reverses, if we were to recreate
//     // the CurvedAnimation objects in build, we'd lose
//     // CurvedAnimation._curveDirection.
//     _fadeOpacity = CurvedAnimation(
//       parent: widget.route.animation!,
//       curve: const Interval(0.0, 0.25),
//       reverseCurve: const Interval(0.75, 1.0),
//     );
//     _resize = CurvedAnimation(
//       parent: widget.route.animation!,
//       curve: const Interval(0.25, 0.5),
//       reverseCurve: const Threshold(0.0),
//     );
//   }
//
//   @override
//   Widget build(BuildContext context) {
//     // The menu is shown in three stages (unit timing in brackets):
//     // [0s - 0.25s] - Fade in a rect-sized menu container with the selected item.
//     // [0.25s - 0.5s] - Grow the otherwise empty menu container from the center
//     //   until it's big enough for as many items as we're going to show.
//     // [0.5s - 1.0s] Fade in the remaining visible items from top to bottom.
//     //
//     // When the menu is dismissed we just fade the entire thing out
//     // in the first 0.25s.
//     assert(debugCheckHasMaterialLocalizations(context));
//     final MaterialLocalizations localizations = MaterialLocalizations.of(context);
//     final _DropdownRoute<T> route = widget.route;
//     final List<Widget> children = <Widget>[
//       for (int itemIndex = 0; itemIndex < route.items.length; ++itemIndex)
//         _DropdownMenuItemButton<T>(
//           route: widget.route,
//           padding: widget.padding,
//           buttonRect: widget.buttonRect,
//           constraints: widget.constraints,
//           itemIndex: itemIndex,
//           enableFeedback: widget.enableFeedback,
//         ),
//       ];
//
//     return FadeTransition(
//       opacity: _fadeOpacity,
//       child: CustomPaint(
//         painter: _DropdownMenuPainter(
//           color: widget.dropdownColor ?? Theme.of(context).canvasColor,
//           elevation: route.elevation,
//           selectedIndex: route.selectedIndex,
//           resize: _resize,
//           borderRadius: widget.borderRadius,
//           // This offset is passed as a callback, not a value, because it must
//           // be retrieved at paint time (after layout), not at build time.
//           getSelectedItemOffset: () => route.getItemOffset(route.selectedIndex),
//         ),
//         child: Semantics(
//           scopesRoute: true,
//           namesRoute: true,
//           explicitChildNodes: true,
//           label: localizations.popupMenuLabel,
//           child: ClipRRect(
//             borderRadius: widget.borderRadius ?? BorderRadius.zero,
//             clipBehavior: widget.borderRadius != null
//               ? Clip.antiAlias
//               : Clip.none,
//             child: Material(
//               type: MaterialTypeansparency,
//               textStyle: route.style,
//               child: ScrollConfiguration(
//                 // Dropdown menus should never overscroll or display an overscroll indicator.
//                 // Scrollbars are built-in below.
//                 // Platform must use Theme and ScrollPhysics must be Clamping.
//                 behavior: ScrollConfiguration.of(context).copyWith(
//                   scrollbars: false,
//                   overscroll: false,
//                   physics: const ClampingScrollPhysics(),
//                   platform: Theme.of(context).platform,
//                 ),
//                 child: PrimaryScrollController(
//                   controller: widget.route.scrollController!,
//                   child: Scrollbar(
//                     thumbVisibility: true,
//                     child: ListView(
//                       // Ensure this always inherits the PrimaryScrollController
//                       primary: true,
//                       padding: kMaterialListPadding,
//                       shrinkWrap: true,
//                       children: children,
//                     ),
//                   ),
//                 ),
//               ),
//             ),
//           ),
//         ),
//       ),
//     );
//   }
// }
//
// class _DropdownMenuRouteLayout<T> extends SingleChildLayoutDelegate {
//   _DropdownMenuRouteLayout({
//     required this.buttonRect,
//     required this.route,
//     required this.textDirection,
//   });
//
//   final Rect buttonRect;
//   final _DropdownRoute<T> route;
//   final TextDirection? textDirection;
//
//   @override
//   BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
//     // The maximum height of a simple menu should be one or more rows less than
//     // the view height. This ensures a tappable area outside of the simple menu
//     // with which to dismiss the menu.
//     //   -- https://material.io/design/components/menus.html#usage
//     double maxHeight = math.max(0.0, constraints.maxHeight - 2 * _kMenuItemHeight);
//     if (route.menuMaxHeight != null && route.menuMaxHeight! <= maxHeight) {
//       maxHeight = route.menuMaxHeight!;
//     }
//     // The width of a menu should be at most the view width. This ensures that
//     // the menu does not extend past the left and right edges of the screen.
//     final double width = math.min(constraints.maxWidth, buttonRect.width);
//     return BoxConstraints(
//       minWidth: width,
//       maxWidth: width,
//       maxHeight: maxHeight,
//     );
//   }
//
//   @override
//   Offset getPositionForChild(Size size, Size childSize) {
//     final _MenuLimits menuLimits = route.getMenuLimits(buttonRect, size.height, route.selectedIndex);
//
//     assert(() {
//       final Rect container = Offset.zero & size;
//       if (container.intersect(buttonRect) == buttonRect) {
//         // If the button was entirely on-screen, then verify
//         // that the menu is also on-screen.
//         // If the button was a bit off-screen, then, oh well.
//         assert(menuLimits.top >= 0.0);
//         assert(menuLimits.top + menuLimits.height <= size.height);
//       }
//       return true;
//     }());
//     assert(textDirection != null);
//     final double left;
//     switch (textDirection!) {
//       case TextDirection.rtl:
//         left = clampDouble(buttonRect.right, 0.0, size.width) - childSize.width;
//         break;
//       case TextDirection.ltr:
//         left = clampDouble(buttonRect.left, 0.0, size.width - childSize.width);
//         break;
//     }
//
//     return Offset(left, menuLimits.top);
//   }
//
//   @override
//   bool shouldRelayout(_DropdownMenuRouteLayout<T> oldDelegate) {
//     return buttonRect != oldDelegate.buttonRect || textDirection != oldDelegate.textDirection;
//   }
// }
//
// // We box the return value so that the return value can be null. Otherwise,
// // canceling the route (which returns null) would get confused with actually
// // returning a real null value.
// @immutable
// class _DropdownRouteResult<T> {
//   const _DropdownRouteResult(this.result);
//
//   final T? result;
//
//   @override
//   bool operator ==(Object other) {
//     return other is _DropdownRouteResult<T>
//         && other.result == result;
//   }
//
//   @override
//   int get hashCode => result.hashCode;
// }
//
// class _MenuLimits {
//   const _MenuLimits(this.top, this.bottom, this.height, this.scrollOffset);
//   final double top;
//   final double bottom;
//   final double height;
//   final double scrollOffset;
// }
//
// class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
//   _DropdownRoute({
//     required this.items,
//     required this.padding,
//     required this.buttonRect,
//     required this.selectedIndex,
//     this.elevation = 8,
//     required this.capturedThemes,
//     required this.style,
//     this.barrierLabel,
//     this.itemHeight,
//     this.dropdownColor,
//     this.menuMaxHeight,
//     required this.enableFeedback,
//     this.borderRadius,
//   }) : assert(style != null),
//        itemHeights = List<double>.filled(items.length, itemHeight ?? kMinInteractiveDimension);
//
//   final List<_MenuItem<T>> items;
//   final EdgeInsetsGeometry padding;
//   final Rect buttonRect;
//   final int selectedIndex;
//   final int elevation;
//   final CapturedThemes capturedThemes;
//   final TextStyle style;
//   final double? itemHeight;
//   final Color? dropdownColor;
//   final double? menuMaxHeight;
//   final bool enableFeedback;
//   final BorderRadius? borderRadius;
//
//   final List<double> itemHeights;
//   ScrollController? scrollController;
//
//   @override
//   Duration get transitionDuration => _kDropdownMenuDuration;
//
//   @override
//   bool get barrierDismissible => true;
//
//   @override
//   Color? get barrierColor => null;
//
//   @override
//   final String? barrierLabel;
//
//   @override
//   Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
//     return LayoutBuilder(
//       builder: (BuildContext context, BoxConstraints constraints) {
//         return _DropdownRoutePage<T>(
//           route: this,
//           constraints: constraints,
//           items: items,
//           padding: padding,
//           buttonRect: buttonRect,
//           selectedIndex: selectedIndex,
//           elevation: elevation,
//           capturedThemes: capturedThemes,
//           style: style,
//           dropdownColor: dropdownColor,
//           enableFeedback: enableFeedback,
//           borderRadius: borderRadius,
//         );
//       },
//     );
//   }
//
//   void _dismiss() {
//     if (isActive) {
//       navigator?.removeRoute(this);
//     }
//   }
//
//   double getItemOffset(int index) {
//     double offset = kMaterialListPadding.top;
//     if (items.isNotEmpty && index > 0) {
//       assert(items.length == itemHeights.length);
//       offset += itemHeights
//         .sublist(0, index)
//         .reduce((double total, double height) => total + height);
//     }
//     return offset;
//   }
//
//   // Returns the vertical extent of the menu and the initial scrollOffset
//   // for the ListView that contains the menu items. The vertical center of the
//   // selected item is aligned with the button's vertical center, as far as
//   // that's possible given availableHeight.
//   _MenuLimits getMenuLimits(Rect buttonRect, double availableHeight, int index) {
//     double computedMaxHeight = availableHeight - 2.0 * _kMenuItemHeight;
//     if (menuMaxHeight != null) {
//       computedMaxHeight = math.min(computedMaxHeight, menuMaxHeight!);
//     }
//     final double buttonTop = buttonRect.top;
//     final double buttonBottom = math.min(buttonRect.bottom, availableHeight);
//     final double selectedItemOffset = getItemOffset(index);
//
//     // If the button is placed on the bottom or top of the screen, its top or
//     // bottom may be less than [_kMenuItemHeight] from the edge of the screen.
//     // In this case, we want to change the menu limits to align with the top
//     // or bottom edge of the button.
//     final double topLimit = math.min(_kMenuItemHeight, buttonTop);
//     final double bottomLimit = math.max(availableHeight - _kMenuItemHeight, buttonBottom);
//
//     double menuTop = (buttonTop - selectedItemOffset) - (itemHeights[selectedIndex] - buttonRect.height) / 2.0;
//     double preferredMenuHeight = kMaterialListPadding.vertical;
//     if (items.isNotEmpty) {
//       preferredMenuHeight += itemHeights.reduce((double total, double height) => total + height);
//     }
//
//     // If there are too many elements in the menu, we need to shrink it down
//     // so it is at most the computedMaxHeight.
//     final double menuHeight = math.min(computedMaxHeight, preferredMenuHeight);
//
//
//     ///修改只显示在组件下方
//     if (bottomLimit - buttonRect.bottom < menuHeight) {
//       menuTop = buttonRect.top - menuHeight;
//     } else {
//       menuTop = buttonRect.bottom;
//     }
//
//     double menuBottom = menuTop + menuHeight;
//
//     // If the computed top or bottom of the menu are outside of the range
//     // specified, we need to bring them into range. If the item height is larger
//     // than the button height and the button is at the very bottom or top of the
//     // screen, the menu will be aligned with the bottom or top of the button
//     // respectively.
//     if (menuTop < topLimit) {
//       menuTop = math.min(buttonTop, topLimit);
//       menuBottom = menuTop + menuHeight;
//     }
//
//     if (menuBottom > bottomLimit) {
//       menuBottom = math.max(buttonBottom, bottomLimit);
//       menuTop = menuBottom - menuHeight;
//     }
//
//     if (menuBottom - itemHeights[selectedIndex] / 2.0 < buttonBottom - buttonRect.height / 2.0) {
//       menuBottom = buttonBottom - buttonRect.height / 2.0 + itemHeights[selectedIndex] / 2.0;
//       menuTop = menuBottom - menuHeight;
//     }
//
//     double scrollOffset = 0;
//     // If all of the menu items will not fit within availableHeight then
//     // compute the scroll offset that will line the selected menu item up
//     // with the select item. This is only done when the menu is first
//     // shown - subsequently we leave the scroll offset where the user left
//     // it. This scroll offset is only accurate for fixed height menu items
//     // (the default).
//     if (preferredMenuHeight > computedMaxHeight) {
//       // The offset should be zero if the selected item is in view at the beginning
//       // of the menu. Otherwise, the scroll offset should center the item if possible.
//       scrollOffset = math.max(0.0, selectedItemOffset - (buttonTop - menuTop));
//       // If the selected item's scroll offset is greater than the maximum scroll offset,
//       // set it instead to the maximum allowed scroll offset.
//       scrollOffset = math.min(scrollOffset, preferredMenuHeight - menuHeight);
//     }
//
//     assert((menuBottom - menuTop - menuHeight).abs() < precisionErrorTolerance);
//     return _MenuLimits(menuTop, menuBottom, menuHeight, scrollOffset);
//   }
// }
//
// class _DropdownRoutePage<T> extends StatelessWidget {
//   const _DropdownRoutePage({
//     super.key,
//     required this.route,
//     required this.constraints,
//     this.items,
//     required this.padding,
//     required this.buttonRect,
//     required this.selectedIndex,
//     this.elevation = 8,
//     required this.capturedThemes,
//     this.style,
//     required this.dropdownColor,
//     required this.enableFeedback,
//     this.borderRadius,
//   });
//
//   final _DropdownRoute<T> route;
//   final BoxConstraints constraints;
//   final List<_MenuItem<T>>? items;
//   final EdgeInsetsGeometry padding;
//   final Rect buttonRect;
//   final int selectedIndex;
//   final int elevation;
//   final CapturedThemes capturedThemes;
//   final TextStyle? style;
//   final Color? dropdownColor;
//   final bool enableFeedback;
//   final BorderRadius? borderRadius;
//
//   @override
//   Widget build(BuildContext context) {
//     assert(debugCheckHasDirectionality(context));
//
//     // Computing the initialScrollOffset now, before the items have been laid
//     // out. This only works if the item heights are effectively fixed, i.e. either
//     // DropdownButton.itemHeight is specified or DropdownButton.itemHeight is null
//     // and all of the items' intrinsic heights are less than kMinInteractiveDimension.
//     // Otherwise the initialScrollOffset is just a rough approximation based on
//     // treating the items as if their heights were all equal to kMinInteractiveDimension.
//     if (route.scrollController == null) {
//       final _MenuLimits menuLimits = route.getMenuLimits(buttonRect, constraints.maxHeight, selectedIndex);
//       route.scrollController = ScrollController(initialScrollOffset: menuLimits.scrollOffset);
//     }
//
//     final TextDirection? textDirection = Directionality.maybeOf(context);
//     final Widget menu = _DropdownMenu<T>(
//       route: route,
//       padding: padding.resolve(textDirection),
//       buttonRect: buttonRect,
//       constraints: constraints,
//       dropdownColor: dropdownColor,
//       enableFeedback: enableFeedback,
//       borderRadius: borderRadius,
//     );
//
//     return MediaQuery.removePadding(
//       context: context,
//       removeTop: true,
//       removeBottom: true,
//       removeLeft: true,
//       removeRight: true,
//       child: Builder(
//         builder: (BuildContext context) {
//           return CustomSingleChildLayout(
//             delegate: _DropdownMenuRouteLayout<T>(
//               buttonRect: buttonRect,
//               route: route,
//               textDirection: textDirection,
//             ),
//             child: capturedThemes.wrap(menu),
//           );
//         },
//       ),
//     );
//   }
// }
//
// // This widget enables _DropdownRoute to look up the sizes of
// // each menu item. These sizes are used to compute the offset of the selected
// // item so that _DropdownRoutePage can align the vertical center of the
// // selected item lines up with the vertical center of the dropdown button,
// // as closely as possible.
// class _MenuItem<T> extends SingleChildRenderObjectWidget {
//   const _MenuItem({
//     super.key,
//     required this.onLayout,
//     required this.item,
//   }) : assert(onLayout != null), super(child: item);
//
//   final ValueChanged<Size> onLayout;
//   final DropdownMenuItem<T>? item;
//
//   @override
//   RenderObject createRenderObject(BuildContext context) {
//     return _RenderMenuItem(onLayout);
//   }
//
//   @override
//   void updateRenderObject(BuildContext context, covariant _RenderMenuItem renderObject) {
//     renderObject.onLayout = onLayout;
//   }
// }
//
// class _RenderMenuItem extends RenderProxyBox {
//   _RenderMenuItem(this.onLayout, [RenderBox? child]) : assert(onLayout != null), super(child);
//
//   ValueChanged<Size> onLayout;
//
//   @override
//   void performLayout() {
//     super.performLayout();
//     onLayout(size);
//   }
// }
//
// // The container widget for a menu item created by a [DropdownButton]. It
// // provides the default configuration for [DropdownMenuItem]s, as well as a
// // [DropdownButton]'s hint and disabledHint widgets.
// class _DropdownMenuItemContainer extends StatelessWidget {
//   /// Creates an item for a dropdown menu.
//   ///
//   /// The [child] argument is required.
//   const _DropdownMenuItemContainer({
//     super.key,
//     this.alignment = AlignmentDirectional.centerStart,
//     required this.child,
//   }) : assert(child != null);
//
//   /// The widget below this widget in the tree.
//   ///
//   /// Typically a [Text] widget.
//   final Widget child;
//
//   /// Defines how the item is positioned within the container.
//   ///
//   /// This property must not be null. It defaults to [AlignmentDirectional.centerStart].
//   ///
//   /// See also:
//   ///
//   ///  * [Alignment], a class with convenient constants typically used to
//   ///    specify an [AlignmentGeometry].
//   ///  * [AlignmentDirectional], like [Alignment] for specifying alignments
//   ///    relative to text direction.
//   final AlignmentGeometry alignment;
//
//   @override
//   Widget build(BuildContext context) {
//     return Container(
//       constraints: const BoxConstraints(minHeight: _kMenuItemHeight),
//       alignment: alignment,
//       child: child,
//     );
//   }
// }
//
// /// An item in a menu created by a [DropdownButton].
// ///
// /// The type `T` is the type of the value the entry represents. All the entries
// /// in a given menu must represent values with consistent types.
// class DropdownMenuItem<T> extends _DropdownMenuItemContainer {
//   /// Creates an item for a dropdown menu.
//   ///
//   /// The [child] argument is required.
//   const DropdownMenuItem({
//     super.key,
//     this.onTap,
//     this.value,
//     this.enabled = true,
//     super.alignment,
//     required super.child,
//   }) : assert(child != null);
//
//   /// Called when the dropdown menu item is tapped.
//   final VoidCallback? onTap;
//
//   /// The value to return if the user selects this menu item.
//   ///
//   /// Eventually returned in a call to [DropdownButton.onChanged].
//   final T? value;
//
//   /// Whether or not a user can select this menu item.
//   ///
//   /// Defaults to `true`.
//   final bool enabled;
// }
//
// /// An inherited widget that causes any descendant [DropdownButton]
// /// widgets to not include their regular underline.
// ///
// /// This is used by [DataTable] to remove the underline from any
// /// [DropdownButton] widgets placed within material data tables, as
// /// required by the Material Design specification.
// class DropdownButtonHideUnderline extends InheritedWidget {
//   /// Creates a [DropdownButtonHideUnderline]. A non-null [child] must
//   /// be given.
//   const DropdownButtonHideUnderline({
//     super.key,
//     required super.child,
//   }) : assert(child != null);
//
//   /// Returns whether the underline of [DropdownButton] widgets should
//   /// be hidden.
//   static bool at(BuildContext context) {
//     return context.dependOnInheritedWidgetOfExactType<DropdownButtonHideUnderline>() != null;
//   }
//
//   @override
//   bool updateShouldNotify(DropdownButtonHideUnderline oldWidget) => false;
// }
//
// /// A Material Design button for selecting from a list of items.
// ///
// /// A dropdown button lets the user select from a number of items. The button
// /// shows the currently selected item as well as an arrow that opens a menu for
// /// selecting another item.
// ///
// /// {@youtube 560 315 https://www.youtube.com/watch?v=ZzQ_PWrFihg}
// ///
// /// One ancestor must be a [Material] widget and typically this is
// /// provided by the app's [Scaffold].
// ///
// /// The type `T` is the type of the [value] that each dropdown item represents.
// /// All the entries in a given menu must represent values with consistent types.
// /// Typically, an enum is used. Each [DropdownMenuItem] in [items] must be
// /// specialized with that same type argument.
// ///
// /// The [onChanged] callback should update a state variable that defines the
// /// dropdown's value. It should also call [State.setState] to rebuild the
// /// dropdown with the new value.
// ///
// /// {@tool dartpad}
// /// This sample shows a `DropdownButton` with a large arrow icon,
// /// purple text style, and bold purple underline, whose value is one of "One",
// /// "Two", "Free", or "Four".
// ///
// /// ![](https://flutter.github.io/assets-for-api-docs/assets/material/dropdown_button.png)
// ///
// /// ** See code in examples/api/lib/material/dropdown/dropdown_button.0.dart **
// /// {@end-tool}
// ///
// /// If the [onChanged] callback is null or the list of [items] is null
// /// then the dropdown button will be disabled, i.e. its arrow will be
// /// displayed in grey and it will not respond to input. A disabled button
// /// will display the [disabledHint] widget if it is non-null. However, if
// /// [disabledHint] is null and [hint] is non-null, the [hint] widget will
// /// instead be displayed.
// ///
// /// Requires one of its ancestors to be a [Material] widget.
// ///
// /// See also:
// ///
// ///  * [DropdownButtonFormField], which integrates with the [Form] widget.
// ///  * [DropdownMenuItem], the class used to represent the [items].
// ///  * [DropdownButtonHideUnderline], which prevents its descendant dropdown buttons
// ///    from displaying their underlines.
// ///  * [ElevatedButton], [TextButton], ordinary buttons that trigger a single action.
// ///  * <https://material.io/design/components/menus.html#dropdown-menu>
// class DropdownButton<T> extends StatefulWidget {
//   /// Creates a dropdown button.
//   ///
//   /// The [items] must have distinct values. If [value] isn't null then it
//   /// must be equal to one of the [DropdownMenuItem] values. If [items] or
//   /// [onChanged] is null, the button will be disabled, the down arrow
//   /// will be greyed out.
//   ///
//   /// If [value] is null and the button is enabled, [hint] will be displayed
//   /// if it is non-null.
//   ///
//   /// If [value] is null and the button is disabled, [disabledHint] will be displayed
//   /// if it is non-null. If [disabledHint] is null, then [hint] will be displayed
//   /// if it is non-null.
//   ///
//   /// The [elevation] and [iconSize] arguments must not be null (they both have
//   /// defaults, so do not need to be specified). The boolean [isDense] and
//   /// [isExpanded] arguments must not be null.
//   ///
//   /// The [autofocus] argument must not be null.
//   ///
//   /// The [dropdownColor] argument specifies the background color of the
//   /// dropdown when it is open. If it is null, the current theme's
//   /// [ThemeData.canvasColor] will be used instead.
//   DropdownButton({
//     super.key,
//     required this.items,
//     this.selectedItemBuilder,
//     this.value,
//     this.hint,
//     this.disabledHint,
//     required this.onChanged,
//     this.onTap,
//     this.elevation = 8,
//     this.style,
//     this.underline,
//     this.icon,
//     this.iconDisabledColor,
//     this.iconEnabledColor,
//     this.iconSize = 24.0,
//     this.isDense = false,
//     this.isExpanded = false,
//     this.itemHeight = kMinInteractiveDimension,
//     this.focusColor,
//     this.focusNode,
//     this.autofocus = false,
//     this.dropdownColor,
//     this.menuMaxHeight,
//     this.enableFeedback,
//     this.alignment = AlignmentDirectional.centerStart,
//     this.borderRadius,
//     // When adding new arguments, consider adding similar arguments to
//     // DropdownButtonFormField.
//   }) : assert(items == null || items.isEmpty || value == null ||
//               items.where((DropdownMenuItem<T> item) {
//                 return item.value == value;
//               }).length == 1,
//                 "There should be exactly one item with [DropdownButton]'s value: "
//                 '$value. \n'
//                 'Either zero or 2 or more [DropdownMenuItem]s were detected '
//                 'with the same value',
//               ),
//        assert(elevation != null),
//        assert(iconSize != null),
//        assert(isDense != null),
//        assert(isExpanded != null),
//        assert(autofocus != null),
//        assert(itemHeight == null || itemHeight >=  kMinInteractiveDimension),
//        _inputDecoration = null,
//        _isEmpty = false,
//        _isFocused = false;
//
//   DropdownButton._formField({
//     super.key,
//     required this.items,
//     this.selectedItemBuilder,
//     this.value,
//     this.hint,
//     this.disabledHint,
//     required this.onChanged,
//     this.onTap,
//     this.elevation = 8,
//     this.style,
//     this.underline,
//     this.icon,
//     this.iconDisabledColor,
//     this.iconEnabledColor,
//     this.iconSize = 24.0,
//     this.isDense = false,
//     this.isExpanded = false,
//     this.itemHeight = kMinInteractiveDimension,
//     this.focusColor,
//     this.focusNode,
//     this.autofocus = false,
//     this.dropdownColor,
//     this.menuMaxHeight,
//     this.enableFeedback,
//     this.alignment = AlignmentDirectional.centerStart,
//     this.borderRadius,
//     required InputDecoration inputDecoration,
//     required bool isEmpty,
//     required bool isFocused,
//   }) : assert(items == null || items.isEmpty || value == null ||
//               items.where((DropdownMenuItem<T> item) {
//                 return item.value == value;
//               }).length == 1,
//                 "There should be exactly one item with [DropdownButtonFormField]'s value: "
//                 '$value. \n'
//                 'Either zero or 2 or more [DropdownMenuItem]s were detected '
//                 'with the same value',
//               ),
//        assert(elevation != null),
//        assert(iconSize != null),
//        assert(isDense != null),
//        assert(isExpanded != null),
//        assert(autofocus != null),
//        assert(itemHeight == null || itemHeight >=  kMinInteractiveDimension),
//        assert(isEmpty != null),
//        assert(isFocused != null),
//        _inputDecoration = inputDecoration,
//        _isEmpty = isEmpty,
//        _isFocused = isFocused;
//
//   /// The list of items the user can select.
//   ///
//   /// If the [onChanged] callback is null or the list of items is null
//   /// then the dropdown button will be disabled, i.e. its arrow will be
//   /// displayed in grey and it will not respond to input.
//   final List<DropdownMenuItem<T>>? items;
//
//   /// The value of the currently selected [DropdownMenuItem].
//   ///
//   /// If [value] is null and the button is enabled, [hint] will be displayed
//   /// if it is non-null.
//   ///
//   /// If [value] is null and the button is disabled, [disabledHint] will be displayed
//   /// if it is non-null. If [disabledHint] is null, then [hint] will be displayed
//   /// if it is non-null.
//   final T? value;
//
//   /// A placeholder widget that is displayed by the dropdown button.
//   ///
//   /// If [value] is null and the dropdown is enabled ([items] and [onChanged] are non-null),
//   /// this widget is displayed as a placeholder for the dropdown button's value.
//   ///
//   /// If [value] is null and the dropdown is disabled and [disabledHint] is null,
//   /// this widget is used as the placeholder.
//   final Widget? hint;
//
//   /// A preferred placeholder widget that is displayed when the dropdown is disabled.
//   ///
//   /// If [value] is null, the dropdown is disabled ([items] or [onChanged] is null),
//   /// this widget is displayed as a placeholder for the dropdown button's value.
//   final Widget? disabledHint;
//
//   /// {@template flutter.material.dropdownButton.onChanged}
//   /// Called when the user selects an item.
//   ///
//   /// If the [onChanged] callback is null or the list of [DropdownButton.items]
//   /// is null then the dropdown button will be disabled, i.e. its arrow will be
//   /// displayed in grey and it will not respond to input. A disabled button
//   /// will display the [DropdownButton.disabledHint] widget if it is non-null.
//   /// If [DropdownButton.disabledHint] is also null but [DropdownButton.hint] is
//   /// non-null, [DropdownButton.hint] will instead be displayed.
//   /// {@endtemplate}
//   final ValueChanged<T?>? onChanged;
//
//   /// Called when the dropdown button is tapped.
//   ///
//   /// This is distinct from [onChanged], which is called when the user
//   /// selects an item from the dropdown.
//   ///
//   /// The callback will not be invoked if the dropdown button is disabled.
//   final VoidCallback? onTap;
//
//   /// A builder to customize the dropdown buttons corresponding to the
//   /// [DropdownMenuItem]s in [items].
//   ///
//   /// When a [DropdownMenuItem] is selected, the widget that will be displayed
//   /// from the list corresponds to the [DropdownMenuItem] of the same index
//   /// in [items].
//   ///
//   /// {@tool dartpad}
//   /// This sample shows a `DropdownButton` with a button with [Text] that
//   /// corresponds to but is unique from [DropdownMenuItem].
//   ///
//   /// ** See code in examples/api/lib/material/dropdown/dropdown_button.selected_item_builder.0.dart **
//   /// {@end-tool}
//   ///
//   /// If this callback is null, the [DropdownMenuItem] from [items]
//   /// that matches [value] will be displayed.
//   final DropdownButtonBuilder? selectedItemBuilder;
//
//   /// The z-coordinate at which to place the menu when open.
//   ///
//   /// The following elevations have defined shadows: 1, 2, 3, 4, 6, 8, 9, 12,
//   /// 16, and 24. See [kElevationToShadow].
//   ///
//   /// Defaults to 8, the appropriate elevation for dropdown buttons.
//   final int elevation;
//
//   /// The text style to use for text in the dropdown button and the dropdown
//   /// menu that appears when you tap the button.
//   ///
//   /// To use a separate text style for selected item when it's displayed within
//   /// the dropdown button, consider using [selectedItemBuilder].
//   ///
//   /// {@tool dartpad}
//   /// This sample shows a `DropdownButton` with a dropdown button text style
//   /// that is different than its menu items.
//   ///
//   /// ** See code in examples/api/lib/material/dropdown/dropdown_button.style.0.dart **
//   /// {@end-tool}
//   ///
//   /// Defaults to the [TextTheme.subtitle1] value of the current
//   /// [ThemeData.textTheme] of the current [Theme].
//   final TextStyle? style;
//
//   /// The widget to use for drawing the drop-down button's underline.
//   ///
//   /// Defaults to a 0.0 width bottom border with color 0xFFBDBDBD.
//   final Widget? underline;
//
//   /// The widget to use for the drop-down button's icon.
//   ///
//   /// Defaults to an [Icon] with the [Icons.arrow_drop_down] glyph.
//   final Widget? icon;
//
//   /// The color of any [Icon] descendant of [icon] if this button is disabled,
//   /// i.e. if [onChanged] is null.
//   ///
//   /// Defaults to [MaterialColor.shade400] of [Colors.grey] when the theme's
//   /// [ThemeData.brightness] is [Brightness.light] and to
//   /// [Colors.white10] when it is [Brightness.dark]
//   final Color? iconDisabledColor;
//
//   /// The color of any [Icon] descendant of [icon] if this button is enabled,
//   /// i.e. if [onChanged] is defined.
//   ///
//   /// Defaults to [MaterialColor.shade700] of [Colors.grey] when the theme's
//   /// [ThemeData.brightness] is [Brightness.light] and to
//   /// [Colors.white70] when it is [Brightness.dark]
//   final Color? iconEnabledColor;
//
//   /// The size to use for the drop-down button's down arrow icon button.
//   ///
//   /// Defaults to 24.0.
//   final double iconSize;
//
//   /// Reduce the button's height.
//   ///
//   /// By default this button's height is the same as its menu items' heights.
//   /// If isDense is true, the button's height is reduced by about half. This
//   /// can be useful when the button is embedded in a container that adds
//   /// its own decorations, like [InputDecorator].
//   final bool isDense;
//
//   /// Set the dropdown's inner contents to horizontally fill its parent.
//   ///
//   /// By default this button's inner width is the minimum size of its contents.
//   /// If [isExpanded] is true, the inner width is expanded to fill its
//   /// surrounding container.
//   final bool isExpanded;
//
//   /// If null, then the menu item heights will vary according to each menu item's
//   /// intrinsic height.
//   ///
//   /// The default value is [kMinInteractiveDimension], which is also the minimum
//   /// height for menu items.
//   ///
//   /// If this value is null and there isn't enough vertical room for the menu,
//   /// then the menu's initial scroll offset may not align the selected item with
//   /// the dropdown button. That's because, in this case, the initial scroll
//   /// offset is computed as if all of the menu item heights were
//   /// [kMinInteractiveDimension].
//   final double? itemHeight;
//
//   /// The color for the button's [Material] when it has the input focus.
//   final Color? focusColor;
//
//   /// {@macro flutter.widgets.Focus.focusNode}
//   final FocusNode? focusNode;
//
//   /// {@macro flutter.widgets.Focus.autofocus}
//   final bool autofocus;
//
//   /// The background color of the dropdown.
//   ///
//   /// If it is not provided, the theme's [ThemeData.canvasColor] will be used
//   /// instead.
//   final Color? dropdownColor;
//
//   /// The maximum height of the menu.
//   ///
//   /// The maximum height of the menu must be at least one row shorter than
//   /// the height of the app's view. This ensures that a tappable area
//   /// outside of the simple menu is present so the user can dismiss the menu.
//   ///
//   /// If this property is set above the maximum allowable height threshold
//   /// mentioned above, then the menu defaults to being padded at the top
//   /// and bottom of the menu by at one menu item's height.
//   final double? menuMaxHeight;
//
//   /// Whether detected gestures should provide acoustic and/or haptic feedback.
//   ///
//   /// For example, on Android a tap will produce a clicking sound and a
//   /// long-press will produce a short vibration, when feedback is enabled.
//   ///
//   /// By default, platform-specific feedback is enabled.
//   ///
//   /// See also:
//   ///
//   ///  * [Feedback] for providing platform-specific feedback to certain actions.
//   final bool? enableFeedback;
//
//   /// Defines how the hint or the selected item is positioned within the button.
//   ///
//   /// This property must not be null. It defaults to [AlignmentDirectional.centerStart].
//   ///
//   /// See also:
//   ///
//   ///  * [Alignment], a class with convenient constants typically used to
//   ///    specify an [AlignmentGeometry].
//   ///  * [AlignmentDirectional], like [Alignment] for specifying alignments
//   ///    relative to text direction.
//   final AlignmentGeometry alignment;
//
//   /// Defines the corner radii of the menu's rounded rectangle shape.
//   final BorderRadius? borderRadius;
//
//   final InputDecoration? _inputDecoration;
//
//   final bool _isEmpty;
//
//   final bool _isFocused;
//
//   @override
//   State<DropdownButton<T>> createState() => _DropdownButtonState<T>();
// }
//
// class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindingObserver {
//   int? _selectedIndex;
//   _DropdownRoute<T>? _dropdownRoute;
//   Orientation? _lastOrientation;
//   FocusNode? _internalNode;
//   FocusNode? get focusNode => widget.focusNode ?? _internalNode;
//   bool _hasPrimaryFocus = false;
//   late Map<Type, Action<Intent>> _actionMap;
//
//   // Only used if needed to create _internalNode.
//   FocusNode _createFocusNode() {
//     return FocusNode(debugLabel: '${widget.runtimeType}');
//   }
//
//   @override
//   void initState() {
//     super.initState();
//     _updateSelectedIndex();
//     if (widget.focusNode == null) {
//       _internalNode ??= _createFocusNode();
//     }
//     _actionMap = <Type, Action<Intent>>{
//       ActivateIntent: CallbackAction<ActivateIntent>(
//         onInvoke: (ActivateIntent intent) => _handleTap(),
//       ),
//       ButtonActivateIntent: CallbackAction<ButtonActivateIntent>(
//         onInvoke: (ButtonActivateIntent intent) => _handleTap(),
//       ),
//     };
//     focusNode!.addListener(_handleFocusChanged);
//   }
//
//   @override
//   void dispose() {
//     WidgetsBinding.instance.removeObserver(this);
//     _removeDropdownRoute();
//     focusNode!.removeListener(_handleFocusChanged);
//     _internalNode?.dispose();
//     super.dispose();
//   }
//
//   void _removeDropdownRoute() {
//     _dropdownRoute?._dismiss();
//     _dropdownRoute = null;
//     _lastOrientation = null;
//   }
//
//   void _handleFocusChanged() {
//     if (_hasPrimaryFocus != focusNode!.hasPrimaryFocus) {
//       setState(() {
//         _hasPrimaryFocus = focusNode!.hasPrimaryFocus;
//       });
//     }
//   }
//
//
//   @override
//   void didUpdateWidget(DropdownButton<T> oldWidget) {
//     super.didUpdateWidget(oldWidget);
//     if (widget.focusNode != oldWidget.focusNode) {
//       oldWidget.focusNode?.removeListener(_handleFocusChanged);
//       if (widget.focusNode == null) {
//         _internalNode ??= _createFocusNode();
//       }
//       _hasPrimaryFocus = focusNode!.hasPrimaryFocus;
//       focusNode!.addListener(_handleFocusChanged);
//     }
//     _updateSelectedIndex();
//   }
//
//   void _updateSelectedIndex() {
//     if (widget.items == null
//         || widget.items!.isEmpty
//         || (widget.value == null &&
//             widget.items!
//                 .where((DropdownMenuItem<T> item) => item.enabled && item.value == widget.value)
//                 .isEmpty)) {
//       _selectedIndex = null;
//       return;
//     }
//
//     assert(widget.items!.where((DropdownMenuItem<T> item) => item.value == widget.value).length == 1);
//     for (int itemIndex = 0; itemIndex < widget.items!.length; itemIndex++) {
//       if (widget.items![itemIndex].value == widget.value) {
//         _selectedIndex = itemIndex;
//         return;
//       }
//     }
//   }
//
//   TextStyle? get _textStyle => widget.style ?? Theme.of(context).textTheme.titleLarge;
//
//   void _handleTap() {
//     final TextDirection? textDirection = Directionality.maybeOf(context);
//     final EdgeInsetsGeometry menuMargin = ButtonTheme.of(context).alignedDropdown
//       ? _kAlignedMenuMargin
//       : _kUnalignedMenuMargin;
//
//     final List<_MenuItem<T>> menuItems = <_MenuItem<T>>[
//     for (int index = 0; index < widget.items!.length; index += 1)
//       _MenuItem<T>(
//         item: widget.items![index],
//         onLayout: (Size size) {
//           // If [_dropdownRoute] is null and onLayout is called, this means
//           // that performLayout was called on a _DropdownRoute that has not
//           // left the widget tree but is already on its way out.
//           //
//           // Since onLayout is used primarily to collect the desired heights
//           // of each menu item before laying them out, not having the _DropdownRoute
//           // collect each item's height to lay out is fine since the route is
//           // already on its way out.
//           if (_dropdownRoute == null) {
//             return;
//           }
//
//           _dropdownRoute!.itemHeights[index] = size.height;
//         },
//       ),
//     ];
//
//     final NavigatorState navigator = Navigator.of(context);
//     assert(_dropdownRoute == null);
//     final RenderBox itemBox = context.findRenderObject()! as RenderBox;
//     final Rect itemRect = itemBox.localToGlobal(Offset.zero, ancestor: navigator.context.findRenderObject()) & itemBox.size;
//     _dropdownRoute = _DropdownRoute<T>(
//       items: menuItems,
//       buttonRect: menuMargin.resolve(textDirection).inflateRect(itemRect),
//       padding: _kMenuItemPadding.resolve(textDirection),
//       selectedIndex: _selectedIndex ?? 0,
//       elevation: widget.elevation,
//       capturedThemes: InheritedTheme.capture(from: context, to: navigator.context),
//       style: _textStyle!,
//       barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
//       itemHeight: widget.itemHeight,
//       dropdownColor: widget.dropdownColor,
//       menuMaxHeight: widget.menuMaxHeight,
//       enableFeedback: widget.enableFeedback ?? true,
//       borderRadius: widget.borderRadius,
//     );
//
//     focusNode?.requestFocus();
//     navigator.push(_dropdownRoute!).then<void>((_DropdownRouteResult<T>? newValue) {
//       _removeDropdownRoute();
//       if (!mounted || newValue == null) {
//         return;
//       }
//       widget.onChanged?.call(newValue.result);
//     });
//
//     widget.onTap?.call();
//   }
//
//   // When isDense is true, reduce the height of this button from _kMenuItemHeight to
//   // _kDenseButtonHeight, but don't make it smaller than the text that it contains.
//   // Similarly, we don't reduce the height of the button so much that its icon
//   // would be clipped.
//   double get _denseButtonHeight {
//     final double fontSize = _textStyle!.fontSize ?? Theme.of(context).textTheme.titleLarge!.fontSize!;
//     return math.max(fontSize, math.max(widget.iconSize, _kDenseButtonHeight));
//   }
//
//   Color get _iconColor {
//     // These colors are not defined in the Material Design spec.
//     if (_enabled) {
//       if (widget.iconEnabledColor != null) {
//         return widget.iconEnabledColor!;
//       }
//
//       switch (Theme.of(context).brightness) {
//         case Brightness.light:
//           return Colors.grey.shade700;
//         case Brightness.dark:
//           return Colors.white70;
//       }
//     } else {
//       if (widget.iconDisabledColor != null) {
//         return widget.iconDisabledColor!;
//       }
//
//       switch (Theme.of(context).brightness) {
//         case Brightness.light:
//           return Colors.grey.shade400;
//         case Brightness.dark:
//           return Colors.white10;
//       }
//     }
//   }
//
//   bool get _enabled => widget.items != null && widget.items!.isNotEmpty && widget.onChanged != null;
//
//   Orientation _getOrientation(BuildContext context) {
//     Orientation? result = MediaQuery.maybeOf(context)?.orientation;
//     if (result == null) {
//       // If there's no MediaQuery, then use the window aspect to determine
//       // orientation.
//       final Size size = WidgetsBinding.instance.window.physicalSize;
//       result = size.width > size.height ? Orientation.landscape : Orientation.portrait;
//     }
//     return result;
//   }
//
//   @override
//   Widget build(BuildContext context) {
//     assert(debugCheckHasMaterial(context));
//     assert(debugCheckHasMaterialLocalizations(context));
//     final Orientation newOrientation = _getOrientation(context);
//     _lastOrientation ??= newOrientation;
//     if (newOrientation != _lastOrientation) {
//       _removeDropdownRoute();
//       _lastOrientation = newOrientation;
//     }
//
//     // The width of the button and the menu are defined by the widest
//     // item and the width of the hint.
//     // We should explicitly type the items list to be a list of <Widget>,
//     // otherwise, no explicit type adding items maybe trigger a crash/failure
//     // when hint and selectedItemBuilder are provided.
//     final List<Widget> items = widget.selectedItemBuilder == null
//       ? (widget.items != null ? List<Widget>.of(widget.items!) : <Widget>[])
//       : List<Widget>.of(widget.selectedItemBuilder!(context));
//
//     int? hintIndex;
//     if (widget.hint != null || (!_enabled && widget.disabledHint != null)) {
//       Widget displayedHint = _enabled ? widget.hint! : widget.disabledHint ?? widget.hint!;
//       if (widget.selectedItemBuilder == null) {
//         displayedHint = _DropdownMenuItemContainer(alignment: widget.alignment, child: displayedHint);
//       }
//
//       hintIndex = items.length;
//       items.add(DefaultTextStyle(
//         style: _textStyle!.copyWith(color: Theme.of(context).hintColor),
//         child: IgnorePointer(
//           ignoringSemantics: false,
//           child: displayedHint,
//         ),
//       ));
//     }
//
//     final EdgeInsetsGeometry padding = ButtonTheme.of(context).alignedDropdown
//       ? _kAlignedButtonPadding
//       : _kUnalignedButtonPadding;
//
//     // If value is null (then _selectedIndex is null) then we
//     // display the hint or nothing at all.
//     final Widget innerItemsWidget;
//     if (items.isEmpty) {
//       innerItemsWidget = Container();
//     } else {
//       innerItemsWidget = IndexedStack(
//         index: _selectedIndex ?? hintIndex,
//         alignment: widget.alignment,
//         children: widget.isDense ? items : items.map((Widget item) {
//           return widget.itemHeight != null
//             ? SizedBox(height: widget.itemHeight, child: item)
//             : Column(mainAxisSize: MainAxisSize.min, children: <Widget>[item]);
//         }).toList(),
//       );
//     }
//
//     const Icon defaultIcon = Icon(Icons.arrow_drop_down);
//
//     Widget result = DefaultTextStyle(
//       style: _enabled ? _textStyle! : _textStyle!.copyWith(color: Theme.of(context).disabledColor),
//       child: Container(
//         padding: padding.resolve(Directionality.of(context)),
//         height: widget.isDense ? _denseButtonHeight : null,
//         child: Row(
//           mainAxisAlignment: MainAxisAlignment.spaceBetween,
//           mainAxisSize: MainAxisSize.min,
//           children: <Widget>[
//             if (widget.isExpanded)
//               Expanded(child: innerItemsWidget)
//             else
//               innerItemsWidget,
//             IconTheme(
//               data: IconThemeData(
//                 color: _iconColor,
//                 size: widget.iconSize,
//               ),
//               child: widget.icon ?? defaultIcon,
//             ),
//           ],
//         ),
//       ),
//     );
//
//     if (!DropdownButtonHideUnderline.at(context)) {
//       final double bottom = (widget.isDense || widget.itemHeight == null) ? 0.0 : 8.0;
//       result = Stack(
//         children: <Widget>[
//           result,
//           Positioned(
//             left: 0.0,
//             right: 0.0,
//             bottom: bottom,
//             child: widget.underline ?? Container(
//               height: 1.0,
//               decoration: const BoxDecoration(
//                 border: Border(
//                   bottom: BorderSide(
//                     color: Color(0xFFBDBDBD),
//                     width: 0.0,
//                   ),
//                 ),
//               ),
//             ),
//           ),
//         ],
//       );
//     }
//
//     final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor>(
//       MaterialStateMouseCursor.clickable,
//       <MaterialState>{
//         if (!_enabled) MaterialState.disabled,
//       },
//     );
//
//     if (widget._inputDecoration != null) {
//       result = InputDecorator(
//         decoration: widget._inputDecoration!,
//         isEmpty: widget._isEmpty,
//         isFocused: widget._isFocused,
//         child: result,
//       );
//     }
//
//     return Semantics(
//       button: true,
//       child: Actions(
//         actions: _actionMap,
//         child: InkWell(
//           mouseCursor: effectiveMouseCursor,
//           onTap: _enabled ? _handleTap : null,
//           canRequestFocus: _enabled,
//           borderRadius: widget.borderRadius,
//           focusNode: focusNode,
//           autofocus: widget.autofocus,
//           focusColor: widget.focusColor ?? Theme.of(context).focusColor,
//           enableFeedback: false,
//           child: result,
//         ),
//       ),
//     );
//   }
// }
//
// /// A [FormField] that contains a [DropdownButton].
// ///
// /// This is a convenience widget that wraps a [DropdownButton] widget in a
// /// [FormField].
// ///
// /// A [Form] ancestor is not required. The [Form] simply makes it easier to
// /// save, reset, or validate multiple fields at once. To use without a [Form],
// /// pass a [GlobalKey] to the constructor and use [GlobalKey.currentState] to
// /// save or reset the form field.
// ///
// /// See also:
// ///
// ///  * [DropdownButton], which is the underlying text field without the [Form]
// ///    integration.
// class DropdownButtonFormField<T> extends FormField<T> {
//   /// Creates a [DropdownButton] widget that is a [FormField], wrapped in an
//   /// [InputDecorator].
//   ///
//   /// For a description of the `onSaved`, `validator`, or `autovalidateMode`
//   /// parameters, see [FormField]. For the rest (other than [decoration]), see
//   /// [DropdownButton].
//   ///
//   /// The `items`, `elevation`, `iconSize`, `isDense`, `isExpanded`,
//   /// `autofocus`, and `decoration`  parameters must not be null.
//   DropdownButtonFormField({
//     super.key,
//     required List<DropdownMenuItem<T>>? items,
//     DropdownButtonBuilder? selectedItemBuilder,
//     T? value,
//     Widget? hint,
//     Widget? disabledHint,
//     required this.onChanged,
//     VoidCallback? onTap,
//     int elevation = 8,
//     TextStyle? style,
//     Widget? icon,
//     Color? iconDisabledColor,
//     Color? iconEnabledColor,
//     double iconSize = 24.0,
//     bool isDense = true,
//     bool isExpanded = false,
//     double? itemHeight,
//     Color? focusColor,
//     FocusNode? focusNode,
//     bool autofocus = false,
//     Color? dropdownColor,
//     InputDecoration? decoration,
//     super.onSaved,
//     super.validator,
//     AutovalidateMode? autovalidateMode,
//     double? menuMaxHeight,
//     bool? enableFeedback,
//     AlignmentGeometry alignment = AlignmentDirectional.centerStart,
//     BorderRadius? borderRadius,
//     // When adding new arguments, consider adding similar arguments to
//     // DropdownButton.
//   }) : assert(items == null || items.isEmpty || value == null ||
//               items.where((DropdownMenuItem<T> item) {
//                 return item.value == value;
//               }).length == 1,
//                 "There should be exactly one item with [DropdownButton]'s value: "
//                 '$value. \n'
//                 'Either zero or 2 or more [DropdownMenuItem]s were detected '
//                 'with the same value',
//               ),
//        assert(elevation != null),
//        assert(iconSize != null),
//        assert(isDense != null),
//        assert(isExpanded != null),
//        assert(itemHeight == null || itemHeight >= kMinInteractiveDimension),
//        assert(autofocus != null),
//        decoration = decoration ?? InputDecoration(focusColor: focusColor),
//        super(
//          initialValue: value,
//          autovalidateMode: autovalidateMode ?? AutovalidateMode.disabled,
//          builder: (FormFieldState<T> field) {
//            final _DropdownButtonFormFieldState<T> state = field as _DropdownButtonFormFieldState<T>;
//            final InputDecoration decorationArg =  decoration ?? InputDecoration(focusColor: focusColor);
//            final InputDecoration effectiveDecoration = decorationArg.applyDefaults(
//              Theme.of(field.context).inputDecorationTheme,
//            );
//
//            final bool showSelectedItem = items != null && items.where((DropdownMenuItem<T> item) => item.value == state.value).isNotEmpty;
//            bool isHintOrDisabledHintAvailable() {
//              final bool isDropdownDisabled = onChanged == null || (items == null || items.isEmpty);
//              if (isDropdownDisabled) {
//                return hint != null || disabledHint != null;
//              } else {
//                return hint != null;
//              }
//            }
//            final bool isEmpty = !showSelectedItem && !isHintOrDisabledHintAvailable();
//
//            // An unfocusable Focus widget so that this widget can detect if its
//            // descendants have focus or not.
//            return Focus(
//              canRequestFocus: false,
//              skipTraversal: true,
//              child: Builder(builder: (BuildContext context) {
//                return DropdownButtonHideUnderline(
//                  child: DropdownButton<T>._formField(
//                    items: items,
//                    selectedItemBuilder: selectedItemBuilder,
//                    value: state.value,
//                    hint: hint,
//                    disabledHint: disabledHint,
//                    onChanged: onChanged == null ? null : state.didChange,
//                    onTap: onTap,
//                    elevation: elevation,
//                    style: style,
//                    icon: icon,
//                    iconDisabledColor: iconDisabledColor,
//                    iconEnabledColor: iconEnabledColor,
//                    iconSize: iconSize,
//                    isDense: isDense,
//                    isExpanded: isExpanded,
//                    itemHeight: itemHeight,
//                    focusColor: focusColor,
//                    focusNode: focusNode,
//                    autofocus: autofocus,
//                    dropdownColor: dropdownColor,
//                    menuMaxHeight: menuMaxHeight,
//                    enableFeedback: enableFeedback,
//                    alignment: alignment,
//                    borderRadius: borderRadius,
//                    inputDecoration: effectiveDecoration.copyWith(errorText: field.errorText),
//                    isEmpty: isEmpty,
//                    isFocused: Focus.of(context).hasFocus,
//                  ),
//                );
//              }),
//            );
//          },
//        );
//
//   /// {@macro flutter.material.dropdownButton.onChanged}
//   final ValueChanged<T?>? onChanged;
//
//   /// The decoration to show around the dropdown button form field.
//   ///
//   /// By default, draws a horizontal line under the dropdown button field but
//   /// can be configured to show an icon, label, hint text, and error text.
//   ///
//   /// If not specified, an [InputDecorator] with the `focusColor` set to the
//   /// supplied `focusColor` (if any) will be used.
//   final InputDecoration decoration;
//
//   @override
//   FormFieldState<T> createState() => _DropdownButtonFormFieldState<T>();
// }
//
// class _DropdownButtonFormFieldState<T> extends FormFieldState<T> {
//
//   @override
//   void didChange(T? value) {
//     super.didChange(value);
//     final DropdownButtonFormField<T> dropdownButtonFormField = widget as DropdownButtonFormField<T>;
//     assert(dropdownButtonFormField.onChanged != null);
//     dropdownButtonFormField.onChanged!(value);
//   }
//
//   @override
//   void didUpdateWidget(DropdownButtonFormField<T> oldWidget) {
//     super.didUpdateWidget(oldWidget);
//     if (oldWidget.initialValue != widget.initialValue) {
//       setValue(widget.initialValue);
//     }
//   }
// }
